﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities.Tracking;
using AppToolkit.WF.Utils;
using System.Collections.ObjectModel;

namespace AppToolkit.WF.Services
{
    /// <summary>
    /// <see cref="TrackingParticipant"/> that can be used to expose progress information.
    /// </summary>
    public sealed class WorkflowStateTrackingParticipant : TrackingParticipant
    {
        private readonly ConcurrentDictionary<Guid,WorkflowState> _workflows = new ConcurrentDictionary<Guid, WorkflowState>();

        /// <summary>
        /// When implemented in a derived class, begins asynchronous processing of the tracking record.
        /// </summary>
        /// <returns>
        /// The result of the operation.
        /// </returns>
        /// <param name="record">The generated tracking record.</param><param name="timeout">The time period after which the provider aborts the attempt.</param><param name="callback">The method to be called on completion of the operation.</param><param name="state">A user-defined object that uniquely identifies this asynchronous operation.</param>
        protected override IAsyncResult BeginTrack(TrackingRecord record, TimeSpan timeout, AsyncCallback callback, object state)
        {
            this.Track(record, timeout);
            return new CompletedAsyncResult(callback, state);
        }

        /// <summary>
        /// When implemented in a derived class, represents the end of an asynchronous tracking operation. 
        /// </summary>
        /// <param name="result">The status of the operation.</param>
        protected override void EndTrack(IAsyncResult result)
        {
            CompletedAsyncResult.End(result);
        }

        /// <summary>
        /// When implemented in a derived class, used to synchronously process the tracking record.
        /// </summary>
        /// <param name="record">The generated tracking record.</param><param name="timeout">The time period after which the provider aborts the attempt.</param>
        protected override void Track(TrackingRecord record, TimeSpan timeout)
        {
                if (record is ActivityStateRecord)
                {
                    this.TrackActivityRecord((ActivityStateRecord)record);
                }
                else if (record is WorkflowInstanceRecord)
                {
                    this.TrackWorkflowRecord((WorkflowInstanceRecord)record);
                }
                //else if (record is BookmarkResumptionRecord)
                //{
                //    this.TrackBookmarkRecord((BookmarkResumptionRecord)record);
                //}
                //else if (record is ActivityScheduledRecord)
                //{
                //    this.TrackActivityScheduledRecord((ActivityScheduledRecord)record);
                //}
                //else if (record is CancelRequestedRecord)
                //{
                //    this.TrackCancelRequestedRecord((CancelRequestedRecord)record);
                //}
                //else if (record is FaultPropagationRecord)
                //{
                //    this.TrackFaultPropagationRecord((FaultPropagationRecord)record);
                //}
                else if (record is CustomTrackingRecord)
                {
                    this.TrackCustomRecord((CustomTrackingRecord)record);
                }
        }

        private void TrackCustomRecord(CustomTrackingRecord customTrackingRecord)
        {
            var record = customTrackingRecord as ProgressTrackingRecord;
            if (record != null)
            {
                WorkflowState state = EnsureExistsWorkflowState(record.InstanceId);
                state.Current = record.Current;
                state.Maximum = record.Maximum;
            }
        }

        //private void TrackFaultPropagationRecord(FaultPropagationRecord faultPropagationRecord)
        //{
        //    throw new NotImplementedException();
        //}

        //private void TrackCancelRequestedRecord(CancelRequestedRecord cancelRequestedRecord)
        //{
        //    throw new NotImplementedException();
        //}

        //private void TrackActivityScheduledRecord(ActivityScheduledRecord activityScheduledRecord)
        //{
        //    throw new NotImplementedException();
        //}

        //private void TrackBookmarkRecord(BookmarkResumptionRecord bookmarkResumptionRecord)
        //{
        //    throw new NotImplementedException();
        //}

        private void TrackWorkflowRecord(WorkflowInstanceRecord workflowInstanceRecord)
        {
            WorkflowState state = EnsureExistsWorkflowState(workflowInstanceRecord.InstanceId);
            state.State = workflowInstanceRecord.State;
        }

        private WorkflowState EnsureExistsWorkflowState(Guid instanceID)
        {
            WorkflowState state;

            if (!this._workflows.TryGetValue(instanceID, out state))
            {
                state = new WorkflowState(instanceID);
                if (!_workflows.TryAdd(instanceID, state))
                    throw new Exception("Failed to add new WorkflowState!");
            }
            return state;
        }

        private void TrackActivityRecord(ActivityStateRecord activityStateRecord)
        {
        }


        #region ViewModel API
        /// <summary>
        /// Returns all captured <see cref="WorkflowState"/>s.
        /// </summary>
        public ICollection<WorkflowState> WorkflowStates
        {
            get { return _workflows.Values; }
        }

        /// <summary>
        /// Returns the <see cref="WorkflowState"/> for a given instanceID.
        /// </summary>
        /// <param name="instanceID"></param>
        /// <returns></returns>
        public WorkflowState GetWorkflowState(Guid instanceID)
        {
            WorkflowState state = null;
            this._workflows.TryGetValue(instanceID, out state);
            return state;
        }
        #endregion


//ActivityScheduledRecord
//ActivityStateRecord
//BookmarkResumptionRecord
//CancelRequestedRecord
//CustomTrackingRecord
//FaultPropagationRecord
//WorkflowInstanceRecord


    }
}